//
// Created by Martin on 2022/10/4.
//

#include <iostream>
#include <iomanip>
#include <type_traits>
using namespace std;

//-----------------------------------------------------------------------------
// 主类型归类

template<typename T>
struct is_unsigned_integer
        : std::integral_constant<
            bool,
            std::is_integral<T>::value &&
            std::is_unsigned<T>::value
        > {};

template<typename T>
struct is_signed_integer
        : std::integral_constant<
            bool,
            std::is_integral<T>::value &&
            std::is_signed<T>::value
        > {};

template<typename T>
struct is_float
        : std::integral_constant<
            bool,
            std::is_same<float, typename std::remove_cv<T>::type>::value
        >{};

template<typename T>
struct is_double
        : std::integral_constant<
            bool,
            std::is_same<double, typename std::remove_cv<T>::type>::value ||
            std::is_same<long double, typename std::remove_cv<T>::type>::value
        > {};

//-----------------------------------------------------------------------------
// 次类型归类

template<typename T>
struct is_integral_pointer : std::false_type {};
template<typename T>
struct is_integral_pointer<T*>
{
    static constexpr bool value = std::is_integral<T>::value;
};

template<typename T>
struct is_float_pointer : std::false_type {};
template<typename T>
struct is_float_pointer<T*>
{
    static constexpr bool value = std::is_floating_point<T>::value;
};

//-----------------------------------------------------------------------------
// 测试

#define SHOW(...) std::cout << std::setw(49) << #__VA_ARGS__ << " == " << __VA_ARGS__ << '\n'

class A{};

static void test_selfdefined_type_traits()
{
    cout << std::boolalpha;
    SHOW( is_unsigned_integer<A>::value );
    SHOW( is_unsigned_integer<unsigned int>::value );
    SHOW( is_unsigned_integer<int>::value );
    SHOW( is_unsigned_integer<unsigned char>::value );
    SHOW( is_unsigned_integer<signed char>::value );
    SHOW( is_unsigned_integer<float>::value );
    SHOW( is_unsigned_integer<bool>::value );
    cout << endl;

    SHOW( is_signed_integer<A>::value );
    SHOW( is_signed_integer<unsigned int>::value );
    SHOW( is_signed_integer<int>::value );
    SHOW( is_signed_integer<unsigned char>::value );
    SHOW( is_signed_integer<signed char>::value );
    SHOW( is_signed_integer<float>::value );
    SHOW( is_signed_integer<bool>::value );
    cout << endl;

    SHOW( is_float<float>::value );
    SHOW( is_float<int>::value );
    SHOW( is_float<short>::value );
    SHOW( is_float<double>::value );
    SHOW( is_float<char>::value );
    SHOW( is_float<bool>::value );
    cout << endl;

    SHOW( is_double<float>::value );
    SHOW( is_double<int>::value );
    SHOW( is_double<short>::value );
    SHOW( is_double<double>::value );
    SHOW( is_double<char>::value );
    SHOW( is_double<bool>::value );
    cout << endl;

    SHOW( is_integral_pointer<int*>::value);
    SHOW( is_integral_pointer<float*>::value);
    SHOW( is_integral_pointer<char*>::value);
    SHOW( is_integral_pointer<bool*>::value);
    SHOW( is_integral_pointer<int>::value);
    SHOW( is_integral_pointer<float>::value);
    SHOW( is_integral_pointer<char>::value);
    SHOW( is_integral_pointer<bool>::value);
    cout<<endl;
};

int main()
{
    test_selfdefined_type_traits();
    return 0;
}
